﻿// ===============================================================================
// ScopeAttribute.cs
// EOS Framework
// ===============================================================================
// Copyright (c) EOS Development Group. All rights reserved.
// ===============================================================================

namespace EOS.Framework.Web.Mvc
{
    using System;
    using System.Web;
    using EOS.Framework.Tools;
    using PostSharp.Laos;

    /// <summary>
    /// Specifies where the data should be stored.
    /// </summary>
    public enum ScopeType : byte
    {
        /// <summary>
        /// Data will be saved as long as it is the same page.
        /// </summary>
        Request = 0,
        /// <summary>
        /// Data will be saved during the session.
        /// </summary>
        Session = 1
    }

    /// <summary>
    /// Manage variable lifetime.
    /// </summary>
    [Serializable]
    [AttributeUsage(AttributeTargets.Property)]
    public class ScopeAttribute : OnMethodBoundaryAspect
    {
        /// <summary>
        /// Specifies, how the value should be stored.
        /// </summary>
        private ScopeType _type;
        /// <summary>
        /// The key indentifying the value.
        /// </summary>
        private string _key;

        /// <summary>
        /// Initializes a new instance of the <see cref="ScopeAttribute"/> class.
        /// </summary>
        /// <param name="key">The key, identifying the value in the session.</param>
        /// <exception cref="ArgumentException"><paramref name="key"/> is a string of 
        /// length 0 or contains only blanks.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="key"/> is null
        /// (Nothing in Visual Basic).</exception>
        public ScopeAttribute(string key)
            : this(key, ScopeType.Session)
        { }

        /// <summary>
        /// Initializes a new instance of the <see cref="ScopeAttribute"/> class.
        /// </summary>
        /// <param name="key">The key, identifying the value in the session.</param>
        /// <param name="type">Identifies where the value should be stored.</param>
        /// <exception cref="ArgumentException"><paramref name="key"/> is a string of 
        /// length 0 or contains only blanks.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="key"/> is null
        /// (Nothing in Visual Basic).</exception>
        public ScopeAttribute(string key, ScopeType type)
        {
            if (key == null)
            {
                throw new ArgumentNullException("key");
            }

            if (StringHelper.IsEmptyOrBlanksOnly(key))
            {
                throw new ArgumentException(Properties.Resources.EmptyStringParameter, "key");
            }

            this._key = key;
            this._type = type;
        }

        /// <summary>
        /// Method executed <b>after</b> the body of methods to which this aspect is applied,
        /// even when the method exists with an exception (this method is invoked from
        /// the <b>finally</b> block).
        /// </summary>
        /// <param name="eventArgs">Event arguments specifying which method
        /// is being executed and which are its arguments.</param>
        public override void OnExit(MethodExecutionEventArgs eventArgs)
        {
            object[] args = eventArgs.GetWritableArgumentArray();

            // Getter
            if (args == null || args.Length == 0)
            {
                switch (_type)
                {
                    case ScopeType.Request:
                        if (HttpContext.Current.Items[_key] != null)
                        {
                            eventArgs.ReturnValue = HttpContext.Current.Items[_key];
                        }
                        break;
                    case ScopeType.Session:
                        if (HttpContext.Current.Session[_key] != null)
                        {
                            eventArgs.ReturnValue = HttpContext.Current.Session[_key];
                        }
                        break;
                }
            }
            // Setter
            else
            {
                switch (_type)
                {
                    case ScopeType.Request:
                        HttpContext.Current.Items[_key] = args[0];
                        break;
                    case ScopeType.Session:
                        HttpContext.Current.Session[_key] = args[0];
                        break;
                }
            }
            base.OnEntry(eventArgs);
        }


    }
}
